/*************************************************
* Title：TinyToolKit
* Author：Opportunity 
* Describe：实现UI管理器的主要逻辑
* CreateTime：2020-04-05 20:19:31
* Version：1.0
* Modify Recorder：
*************************************************/

using System.Collections.Generic;
using TinyToolKit.AssetLoad;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

namespace TinyToolKit.UI
{
    public class TUIManager : ManagerBase 
    {
        #region variable
        //存储所有窗体的路径，key是窗体预设名称，value是窗体预设路径
        private Dictionary<string, string> _allUiFormsPaths;
        //存储所有加载的UI窗体
        private Dictionary<string, UIFormBase> _allUiForms;
        //存储当前加载的UI窗体 
        private Dictionary<string, UIFormBase> _curDisplayUiForms;
        //存储当前所有显示的需要保持顺序的窗体
        private Stack<UIFormBase> _curDisplayUiFormsStack;

        public Dictionary<string, UIFormBase> CurDisplayUIForm => _curDisplayUiForms;

        public Stack<UIFormBase> CurDisplayModalUIForms => _curDisplayUiFormsStack;

        private Transform _canvasRoot;//UI根节点
        private Transform _normalRoot;//全屏幕显示窗体的节点
        private Transform _fixedRoot;//固定显示窗体的的节点
        private Transform _popUpRoot;//弹出窗体的节点
        private Transform _uiScriptsRoot;//UI管理脚本的节点
        private Camera _uiCamera; 

        public RectTransform CanvasRoot => _canvasRoot as  RectTransform;
        public Camera UICamera => _uiCamera;

        private RectTransform _uiMask;
        private Image _uiMaskImage;

        private TResourcesManager _resourcesManager;
        private bool clearAllFormsOnSceneChanged;

        public int AllUIFormsCount
        {
            get
            {
                if (_allUiForms != null)
                    return _allUiForms.Count;
                return 0;
            }
        }

        public int CurDisplayUIFormsCount 
        {
            get
            {
                if (_curDisplayUiForms != null)
                    return _curDisplayUiForms.Count;
                return 0;
            }
        }

        public int CurDisplayUIFormsStackCount 
        {
            get
            {
                if (_curDisplayUiFormsStack != null)
                    return _curDisplayUiFormsStack.Count;
                return 0;
            }
        }
        #endregion

        #region Manager Func
        public override int Priority => 30;

        public override void Init()
        {
            _allUiFormsPaths = new Dictionary<string, string>();
            _allUiForms = new Dictionary<string, UIFormBase>();
            _curDisplayUiForms = new Dictionary<string, UIFormBase>();
            _curDisplayUiFormsStack = new Stack<UIFormBase>();
            
            _resourcesManager = TinyTool.Instance.GetManager<TResourcesManager>();
            
            InitTinyCanvas();

            if (TinyTool.Instance != null && TinyTool.Instance.TinyToolSetting != null)
            {
                ParseUIFormConfig();
                clearAllFormsOnSceneChanged = TinyTool.Instance.TinyToolSetting.clearAllFormsOnSceneChanged;
            }
            else
            {
                TLogTool.Error("TinyTool.Instance 或 TinyToolSetting资源不能为Null");
            }
        }

        public override void UpdateManager()
        {

        }

        public override void OnSceneLoaded(Scene scene, LoadSceneMode mode)
        {
            if (clearAllFormsOnSceneChanged)
                ClearAllUIForms();
        }

        public override void Shutdown()
        {
            _allUiFormsPaths.Clear();
            _allUiForms.Clear();
            _curDisplayUiForms.Clear();
            _curDisplayUiFormsStack.Clear();
            _resourcesManager = null;
            _canvasRoot = null;
            _normalRoot = null;
            _fixedRoot = null;
            _popUpRoot = null;
            _uiScriptsRoot = null;
            _uiCamera = null;
            _uiMask = null;
            _uiMaskImage = null;
        }
        #endregion

        #region Public Func
        /// <summary>
        /// 如果加载方式选择的是自定义，则需要调用该方法设置窗体的配置表
        /// </summary>
        /// <param name="json">配置表</param>
        public void SetUIFormPaths(string json) 
        { 
            if (string.IsNullOrEmpty(json) == false)
            {
                _allUiFormsPaths.Clear();
                UIFormPath formPath = TinyUtility.Json.ToObject<UIFormPath>(json);
                for (int i = 0; i < formPath.UIFormPaths.Count; i++)
                {
                    string uiFormName = formPath.UIFormPaths[i].UIFormName;
                    string uiFormPath = formPath.UIFormPaths[i].UIFormSavePath;
                    if (_allUiFormsPaths.ContainsKey(uiFormName) == false)
                        _allUiFormsPaths.Add(uiFormName, uiFormPath);
                }
            }
        }
        
        /// <summary>
        /// 打开窗体，但需要先加载窗体配置表
        /// </summary>
        /// <param name="uiFormName">窗体的名称</param>
        /// <returns>返回窗体基类</returns>
        public UIFormBase OpenUIForm(string uiFormName) 
        {
            if (string.IsNullOrEmpty(uiFormName)) return null;

            return HandleUIForm(uiFormName, LoadUIForm(uiFormName));
        }

        
        /// <summary>
        /// 打开窗体
        /// </summary>
        /// <param name="uiFormPrefab">窗体的预制体</param>
        /// <returns>返回窗体基类</returns>
        public UIFormBase OpenUIForm(GameObject uiFormPrefab)
        {
            if (uiFormPrefab == null) return null;
            
            return HandleUIForm(uiFormPrefab.name, LoadUIForm(uiFormPrefab));
        }

        /// <summary>
        /// 获取窗体
        /// </summary>
        /// <param name="uiFormName">需要获取的窗体名称</param>
        /// <returns>返回窗体基类</returns>
        public UIFormBase GetUIForm(string uiFormName)
        {
            if (string.IsNullOrEmpty(uiFormName)) return null;

            UIFormBase formBase = null;
            if (_allUiForms.TryGetValue(uiFormName, out formBase))
            {
                return formBase; 
            }
            TLogTool.Info("未查询到：{0}", uiFormName);
            return null; 
        }
        
        /// <summary>
        /// 关闭窗体
        /// </summary>
        /// <param name="uiFormName">需要关闭的窗体名称</param>
        public void CloseUIForm(string uiFormName)
        {
            if (string.IsNullOrEmpty(uiFormName)) return;

            UIFormBase formBase = null;
            if (_allUiForms.TryGetValue(uiFormName, out formBase))
            {
                switch (formBase.UIFormShowType)
                {
                    case UIFormShowType.Simple:
                        HideNormalUIForm(uiFormName);
                        break;
                    case UIFormShowType.Modal:
                        HideStackUIForm(uiFormName);
                        DeactiveUIMask(formBase);
                        break;
                    case UIFormShowType.PauseOthers:
                        HidePauseOthersUIForm(uiFormName);
                        break;
                }
            }
            else
            {
                TLogTool.Info("未查询到：{0}", uiFormName);
            }
        }

        /// <summary>
        /// 关闭所有的UIForms
        /// </summary>
        public void ClearAllUIForms()  
        {
            List<string> uiformPath = new List<string>();
            foreach (var item in _curDisplayUiForms)
            {
                uiformPath.Add(item.Key);
            }

            for (int i = 0; i < uiformPath.Count; i++)
            {
                CloseUIForm(uiformPath[i]);
            }
            _curDisplayUiForms.Clear();
            ClearUIFormsStack();

            foreach (var item in _allUiForms)
            {
                Object.DestroyImmediate(item.Value.gameObject);
            }
            
            _allUiForms.Clear();
        }
        #endregion

        #region Internal Func

        private void InitTinyCanvas()
        {
            GameObject root = GameObject.Find("TinyCanvas");
            if (root == null)
            {
                root = _resourcesManager.LoadAsset<GameObject>(UIManagerDefine.UI_CANVAS_PATH);
                if (root != null)
                {
                    _canvasRoot = GameObject.Instantiate(root).transform;
                    _canvasRoot.name = "TinyCanvas";
                }
            }
            else
            {
                _canvasRoot = root.transform;
            }

            if (TinyTool.Instance != null)
                TinyTool.Instance.transform.SetStandardChild(_canvasRoot);

            _normalRoot = _canvasRoot.Find(UIManagerDefine.UI_NORMALROOT_PATH);
            _fixedRoot = _canvasRoot.Find(UIManagerDefine.UI_FIXEDROOT_PATH);
            _popUpRoot = _canvasRoot.Find(UIManagerDefine.UI_POPUPROOT_PATH);
            _uiScriptsRoot = _canvasRoot.Find(UIManagerDefine.UI_SCRIPTSROOT_PATH);
            _uiCamera = _canvasRoot.Find(UIManagerDefine.UI_CAMERA_PATH).GetComponent<Camera>();
            
            _uiMask = _popUpRoot.Find(UIManagerDefine.UI_UIMASK_PATH) as RectTransform;
            if (_uiMask != null)
            {
                _uiMaskImage = _uiMask.gameObject.GetOrAddComponent<Image>();
                _uiMask.gameObject.SetActive(false);
            }
        }

        private void ParseUIFormConfig()
        {
            UIFormPathType pathType = TinyTool.Instance.TinyToolSetting.uiFormLocalizationPathType;
            string configPath = TinyTool.Instance.TinyToolSetting.uiFormsConfigResPath;

            string jsonMsg = string.Empty;
            switch (pathType)
            {
                case UIFormPathType.Resources:
                    configPath = TinyUtility.Path.GetPathWithoutExtension(configPath);
                    TextAsset textAsset = _resourcesManager.LoadAsset<TextAsset>(configPath);
                    if (textAsset != null)
                        jsonMsg = textAsset.text;
                    else
                        TLogTool.Error("未找到：" + configPath);
                    SetUIFormPaths(jsonMsg);
                    break;
                case UIFormPathType.Custom:
                    break;
            }
        }

        private UIFormBase HandleUIForm(string uiFormName,UIFormBase formBase)  
        {
            if (formBase == null) return null;

            switch (formBase.UIFormShowType)
            {
                case UIFormShowType.Simple:
                    DisplayNormalUIForm(uiFormName);
                    break;
                case UIFormShowType.Modal:
                    if (formBase.isClearOrder) 
                        ClearUIFormsStack();
                    if (formBase.UIFormRaycastType == UIFormRaycastType.Block)
                        ActiveUIMask();
                    formBase.transform.SetAsLastSibling();
                    DisplayStackUIForm(uiFormName);
                    break;
                case UIFormShowType.PauseOthers:
                    DisplayPauseOthersUIForm(uiFormName);
                    break;
            }
            return formBase;
        }
        
        //默认Resources动态加载UI预制体资源
        private UIFormBase LoadUIForm(string uiFormName) 
        {
            if (_allUiForms.TryGetValue(uiFormName, out var formBase))
                return formBase;
            
            GameObject uiFormPrefab;
            string uiFormPath;
            if (_allUiFormsPaths.ContainsKey(uiFormName))
                uiFormPath = _allUiFormsPaths[uiFormName];
            else
            {
                TLogTool.Error(uiFormName + "的窗体路径不存在");
                return null;
            }
            
            if (string.IsNullOrEmpty(uiFormPath) == false)
            {
                if (_canvasRoot == null)
                {
                    TLogTool.Error("CanvasRoot不能为Null");
                    return null;
                }

                int index = uiFormPath.IndexOf("Resources");
                if (index > 0)
                    uiFormPath = uiFormPath.Remove(0, index + 10);
                uiFormPath = TinyUtility.Path.GetPathWithoutExtension(uiFormPath);
                
                uiFormPrefab = _resourcesManager.LoadAsset<GameObject>(uiFormPath);
            }
            else
            {
                TLogTool.Error(uiFormName + "的窗体路径不能为空");
                return null;
            }

            return LoadUIForm(uiFormPrefab);
        }
        
        private UIFormBase LoadUIForm(GameObject uiFormPrefab)
        {
            if (uiFormPrefab == null) return null;
            
            string uiFormName = uiFormPrefab.name;
            if (_allUiForms.TryGetValue(uiFormName, out var formBase))
                return formBase;
            
            formBase = uiFormPrefab.GetComponent<UIFormBase>();
            if (formBase == null)
            {
                TLogTool.Error(uiFormName + "未挂载UIFormBase类");
                return null;
            }

            //判断场景中是否已经添加了该窗体
            formBase = FindExistedForm(formBase.UIFormLayerType, uiFormName);
            if (formBase != null)
            {
                TLogTool.Info("场景中已经存在：{0}，现将该窗体存储并管理", uiFormName);
                formBase.OnInit();
                formBase.gameObject.SetActive(false);
            }
            else
            {
                var uiForm = GameObject.Instantiate(uiFormPrefab);
                uiForm.name = uiFormName;
                formBase = uiForm.GetOrAddComponent<UIFormBase>();
                formBase.OnInit();
                
                switch (formBase.UIFormLayerType)
                {
                    case UIFormLayerType.Normal:
                        uiForm.transform.SetParent(_normalRoot, false);
                        break;
                    case UIFormLayerType.Fixed:
                        uiForm.transform.SetParent(_fixedRoot, false);
                        break;
                    case UIFormLayerType.PopUp:
                        uiForm.transform.SetParent(_popUpRoot, false);
                        break;
                }
                uiForm.SetActive(false);
            }

            formBase.SetUIManager(uiFormName,this);
            
            if (_allUiForms.ContainsKey(uiFormName) == false)
                _allUiForms.Add(uiFormName, formBase);

            return formBase;
        }

        //检查Canvas是否已经包含了窗体，但却没有加入到字典_AllUIForms中 
        private UIFormBase FindExistedForm(UIFormLayerType layerType, string formName)
        {
            Transform target = null;
            switch (layerType)
            {
                case UIFormLayerType.Normal:
                    target = _normalRoot.Find(formName);
                    break;
                case UIFormLayerType.Fixed:
                    target = _fixedRoot.Find(formName);
                    break;
                case UIFormLayerType.PopUp:
                    target = _popUpRoot.Find(formName);
                    break;
            }

            if (target != null)
            {
                UIFormBase formBase = target.GetComponent<UIFormBase>();
                if (formBase != null)
                    return formBase;
            }

            return null;
        }

        private void DisplayNormalUIForm(string uiFormName)
        {
            if (_allUiForms.ContainsKey(uiFormName))
            {
                _allUiForms[uiFormName].OnEnter();
                _allUiForms[uiFormName].transform.SetAsLastSibling();
                
                if (_curDisplayUiForms.ContainsKey(uiFormName) == false)
                    _curDisplayUiForms.Add(uiFormName, _allUiForms[uiFormName]);
            }
        }

        private void HideNormalUIForm(string uiFormName)
        {
            if (_curDisplayUiForms.TryGetValue(uiFormName, out var formBase))
            {
                formBase.OnExit();
                _curDisplayUiForms.Remove(uiFormName);
            }
        }

        //如果当前窗口内有显示其他窗体(即栈内是否有其他UIFormBase)，则先暂停这些窗体
        private void DisplayStackUIForm(string uiFormName)
        {
            UIFormBase topFormBase = null;

            if (_curDisplayUiFormsStack.Count > 0)
            {
                topFormBase = _curDisplayUiFormsStack.Peek();
                topFormBase.OnPause();
            }
            
            if (_allUiForms.TryGetValue(uiFormName, out var formBase))
            {
                formBase = _allUiForms[uiFormName];
                formBase.OnEnter();
                
                if (formBase != topFormBase)
                    _curDisplayUiFormsStack.Push(formBase);
            }
        }

        private void HideStackUIForm(string uiFormName)
        {
            if (_curDisplayUiFormsStack.Count >= 2)
            {
                UIFormBase formBase = _curDisplayUiFormsStack.Pop();
                formBase.OnExit();

                _curDisplayUiFormsStack.Peek().OnResume();
            }
            else if (_curDisplayUiFormsStack.Count == 1)
            {
                UIFormBase formBase = _curDisplayUiFormsStack.Pop();
                formBase.OnExit();
            }
        }

        private void DisplayPauseOthersUIForm(string uiFormName)
        {
            foreach (var item in _curDisplayUiForms)
            {
                if (item.Key != uiFormName)
                {
                    item.Value.OnPause();
                }
            }

            if (_allUiForms.TryGetValue(uiFormName, out var formBase))
            {
                if (_curDisplayUiForms.ContainsKey(uiFormName) == false)
                    _curDisplayUiForms.Add(uiFormName, formBase);
                formBase.OnEnter();
            }
            
            foreach (var item in _curDisplayUiFormsStack)
            {
                if (item != formBase)
                {
                    item.OnPause();
                }
            }
        }

        private void HidePauseOthersUIForm(string uiFormName)
        {
            if (_curDisplayUiForms.TryGetValue(uiFormName, out var formBase))
            {
                formBase.OnExit();
                _curDisplayUiForms.Remove(uiFormName);
            }

            foreach (var item in _curDisplayUiForms)
            {
                item.Value.OnResume();
            }
            foreach (var item in _curDisplayUiFormsStack)
            {
                item.OnResume();
            }
        }

        private void ActiveUIMask()
        {
            _uiMask.gameObject.SetActive(true);
            _uiMask.SetAsLastSibling();//移动到所有兄弟节点的最后位置
        }

        private void DeactiveUIMask(UIFormBase formBase)
        {
            if (_curDisplayUiFormsStack.Count > 0)
            {
                UIFormBase topFormBase = _curDisplayUiFormsStack.Peek();

                if (topFormBase.UIFormRaycastType == UIFormRaycastType.Block)
                {
                    _uiMask.SetAsFirstSibling();
                    _uiMask.gameObject.SetActive(true);
                }
                else
                {
                    _uiMask.SetAsFirstSibling();
                    _uiMask.gameObject.SetActive(false);
                }

                topFormBase.transform.SetAsLastSibling();
            }
            else
            {
                _uiMask.SetAsFirstSibling();
                _uiMask.gameObject.SetActive(false);
            }
        }

        private void ClearUIFormsStack()
        {
            if (_curDisplayUiFormsStack != null && _curDisplayUiFormsStack.Count > 0)
            {
                List<string> temp = new List<string>();
                foreach (UIFormBase formBase in _curDisplayUiFormsStack)
                {
                    foreach (var item in _allUiForms)
                    {
                        if (item.Value == formBase)
                        {
                            temp.Add(item.Key);
                            break;
                        }
                    }
                }

                for (int i = 0; i < temp.Count; i++)
                {
                    CloseUIForm(temp[i]); 
                }
                
                _curDisplayUiFormsStack.Clear();
            }
        }

        private void RemoveNonPersistForm()
        {
            
        }

        #endregion
    }
    
    [System.Serializable]
    public class UIFormPathItem
    {
        public string UIFormName;
        public string UIFormSavePath;

        public UIFormPathItem() { }
        public UIFormPathItem(string UIFormName, string UIFormSavePath)
        {
            this.UIFormName = UIFormName;
            this.UIFormSavePath = UIFormSavePath;
        }
    }

    [System.Serializable]
    public class UIFormPath
    {
        public List<UIFormPathItem> UIFormPaths = new List<UIFormPathItem>();

        public bool Add(string name,string path)
        {
            if (Contains(name) == false)
            {
                UIFormPaths.Add(new UIFormPathItem(name, path));
                return true;
            }
            return false;
        }

        public bool Contains(string name)
        {
            for (int i = 0; i < UIFormPaths.Count; i++)
            {
                if (UIFormPaths[i].UIFormName.Equals(name))
                    return true;
            }
            return false;
        }
    }
}


